package net.wicp.tams.duckula.ops.servicesBusi;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.SortedSet;
import java.util.TreeSet;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.ArrayUtils;

import com.alibaba.fastjson.JSONObject;

import lombok.extern.slf4j.Slf4j;
import net.wicp.tams.common.http.HttpClient;
import net.wicp.tams.common.http.HttpResult;
import net.wicp.tams.commons.Result;
import net.wicp.tams.commons.apiext.StringUtil;
import net.wicp.tams.commons.beans.MonitorInfo;
import net.wicp.tams.commons.constant.dic.YesOrNo;
import net.wicp.tams.duckula.common.ZkClient;
import net.wicp.tams.duckula.common.ZkUtil;
import net.wicp.tams.duckula.common.beans.Task;
import net.wicp.tams.duckula.common.constant.ZkPath;
import net.wicp.tams.duckula.ops.beans.DbInstance;
import net.wicp.tams.duckula.ops.beans.PosShow;
import net.wicp.tams.duckula.ops.beans.Server;

@Slf4j
public class DuckulaAssitImpl implements IDuckulaAssit {
	private String queryServerUrlformat = "http://%s:%s/duckula-server/monitorshow";
	private String startUrlformat = "http://%s:%s/duckula-server/taskstart";
	private String stopUrlformat = "http://%s:%s/duckula-server/taskstop";

	@Override
	public List<Server> findAllServers() {
		List<Server> servers = new ArrayList<>();
		List<String> allServers = ZkUtil.findSubNodes(ZkPath.servers);
		for (String serverName : allServers) {
			Server server = JSONObject.toJavaObject(ZkClient.getInst().getZkData(ZkPath.servers.getPath(serverName)),
					Server.class);
			servers.add(server);
		}
		return servers;
	}

	@Override
	public List<DbInstance> findAllDbInstances() {
		List<DbInstance> dbs = new ArrayList<>();
		List<String> allDbNames = ZkUtil.findSubNodes(ZkPath.dbinsts);
		for (String dbName : allDbNames) {
			DbInstance db = JSONObject.toJavaObject(ZkClient.getInst().getZkData(ZkPath.dbinsts.getPath(dbName)),
					DbInstance.class);
			dbs.add(db);
		}
		return dbs;
	}

	@Override
	public List<Task> findAllTasks() {
		List<Task> tasks = new ArrayList<>();
		List<String> allTaskNames = ZkUtil.findSubNodes(ZkPath.tasks);
		for (String taskNames : allTaskNames) {
			Task tk = JSONObject.toJavaObject(ZkClient.getInst().getZkData(ZkPath.tasks.getPath(taskNames)),
					Task.class);
			tasks.add(tk);
		}
		return tasks;
	}

	@Override
	public List<PosShow> findAllPosForTasks() {
		List<PosShow> poslist = new ArrayList<>();
		List<String> allTaskNames = ZkUtil.findSubNodes(ZkPath.tasks);
		for (String taskName : allTaskNames) {
			PosShow pos = JSONObject.toJavaObject(ZkClient.getInst().getZkData(ZkPath.pos.getPath(taskName)),
					PosShow.class);
			if (pos == null) {
				pos = new PosShow();
			}
			pos.setId(taskName);
			poslist.add(pos);
		}
		return poslist;
	}

	@Override
	public Map<String, Integer> serverRunTaskNum(List<Server> servers) {
		Map<String, Integer> retMap = new HashMap<>();
		for (Server server : servers) {
			retMap.put(server.getIp(), 0);
		}
		List<Task> alltasks = findAllTasks();
		for (Task task : alltasks) {
			if (task.getRun() == YesOrNo.yes) {
				List<String> locks = ZkUtil.lockIps(task.getId());
				for (Server server : servers) {
					if (locks.contains(server.getIp())) {
						int tempNum = retMap.get(server.getIp()).intValue();
						retMap.put(server.getIp(), ++tempNum);
					}
				}
			}
		}
		return retMap;
	}

	@Override
	public Server selServer(String... removeIps) {
		List<Server> servers = findAllServers();
		SortedSet<Server> retSet = new TreeSet<>();
		for (Server server : servers) {
			if (ArrayUtils.contains(removeIps, server.getIp())) {
				continue;
			}
			try {
				JSONObject params = DuckulaUtils.buildClient();
				params.put("needCpu", "false");

				HttpResult res = HttpClient
						.doPost(String.format(queryServerUrlformat, server.getIp(), server.getServerPort()), params);

				JSONObject retobj = (JSONObject) JSONObject.parse(res.getBodyStr());
				MonitorInfo monitorInfoBean = JSONObject.parseObject(retobj.getJSONObject("monitorInfo").toJSONString(),
						MonitorInfo.class);
				server.setMi(monitorInfoBean);
				retSet.add(server);
			} catch (Exception e) {
				log.error("获取服务器信息失败", e);
			}
		}
		if (CollectionUtils.isEmpty(retSet)) {
			return null;
		} else {
			return retSet.first();
		}
	}

	@Override
	public Result startTask(String taskId, Server server, boolean isAuto) {
		if (server == null) {
			return Result.getError("没有可用服务");
		}
		JSONObject params = DuckulaUtils.buildClient();
		params.put("taskId", taskId);
		int jmxPort = StringUtil.buildPort(taskId);
		params.put("jmxPort", jmxPort);
		String url = String.format(startUrlformat, server.getIp(), server.getServerPort());
		log.info("url:{},param:{}", url, params.toJSONString());
		HttpResult res = HttpClient.doPost(url, params);
		JSONObject retobj = (JSONObject) JSONObject.parse(res.getBodyStr());
		if (!"1000".equals(retobj.getString("errorValue"))) {
			log.error("在服务器:[{}]上启动Task[{}]出错:{}", server.getIp(), taskId, retobj.getString("errorDesc"));
			return Result.getError(retobj.getString("errorDesc"));
		} else {
			if (!isAuto) {// 是手动启动改状态,下次将会被自动调用
				Task task = ZkUtil.buidlTask(taskId);
				task.setRun(YesOrNo.yes);
				ZkClient.getInst().updateNode(ZkPath.tasks.getPath(taskId), JSONObject.toJSONString(task));
			}
			return Result.getSuc();
		}
	}

	@Override
	public Result stopTask(String taskId, Server server) {
		String url = String.format(stopUrlformat, server.getIp(), server.getServerPort());
		JSONObject params = DuckulaUtils.buildClient();
		params.put("taskId", taskId);
		int jmxPort = StringUtil.buildPort(taskId);
		params.put("jmxPort", jmxPort);
		log.info("url:{},param:{}", url, params.toJSONString());
		HttpResult res = HttpClient.doPost(url, params);
		JSONObject retobj = (JSONObject) JSONObject.parse(res.getBodyStr());
		if (!"1000".equals(retobj.getString("errorValue"))) {
			log.error("在服务器:[{}]上停止Task[{}]出错:{}", server.getIp(), taskId, retobj.getString("errorDesc"));
			return Result.getError(retobj.getString("errorDesc"));
		} else {// 手动更新需要更新状态,这样不会被自动调用
			Task task = ZkUtil.buidlTask(taskId);
			task.setRun(YesOrNo.no);
			ZkClient.getInst().updateNode(ZkPath.tasks.getPath(taskId), JSONObject.toJSONString(task));
			return Result.getSuc();
		}
	}

}
